using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace XnaDevRu.Bullet
{
	public class SimpleBroadphase : OverlappingPairCache
	{
		private int _maxProxies;
		private List<SimpleBroadphaseProxy> _proxies = new List<SimpleBroadphaseProxy>();

		public SimpleBroadphase()
			: this(16384) { }

		public SimpleBroadphase(int maxProxies)
			: base()
		{
			_maxProxies = maxProxies;
		}

		public override BroadphaseProxy CreateProxy(Vector3 min, Vector3 max, BroadphaseNativeTypes shapeType, object userData, BroadphaseProxy.CollisionFilterGroups collisionFilterGroup, BroadphaseProxy.CollisionFilterGroups collisionFilterMask)
		{
			if (_proxies.Count >= _maxProxies)
			{
                BulletDebug.Assert(false);
				return null; //should never happen, but don't let the game crash ;-)
			}
            BulletDebug.Assert(min.X <= max.X && min.Y <= max.Y && min.Z <= max.Z);

			SimpleBroadphaseProxy proxy = new SimpleBroadphaseProxy(min, max, shapeType, userData, collisionFilterGroup, collisionFilterMask);
			_proxies.Add(proxy);

			return proxy;
		}


		public override void DestroyProxy(BroadphaseProxy proxy)
		{
			RemoveOverlappingPairsContainingProxy(proxy);
			_proxies.Remove(proxy as SimpleBroadphaseProxy);
		}

		public override void SetAabb(BroadphaseProxy proxy, Vector3 aabbMin, Vector3 aabbMax)
		{
			SimpleBroadphaseProxy simpleProxy = GetSimpleProxyFromProxy(proxy);
			simpleProxy.Minimum = aabbMin;
			simpleProxy.Maximum = aabbMax;
		}

		private SimpleBroadphaseProxy GetSimpleProxyFromProxy(BroadphaseProxy proxy)
		{
			return proxy as SimpleBroadphaseProxy;
		}

		public override void RefreshOverlappingPairs()
		{
			for (int i = 0; i < _proxies.Count; i++)
			{
				SimpleBroadphaseProxy proxyA = _proxies[i];

				for (int j = i + 1; j < _proxies.Count; j++)
				{
					SimpleBroadphaseProxy proxyB = _proxies[j];

					if (AabbOverlap(proxyA, proxyB))
					{
						if (FindPair(proxyA, proxyB) == null)
						{
							AddOverlappingPair(proxyA, proxyB);
						}
					}
				}
			}

			CheckOverlapCallback check = new CheckOverlapCallback();
			ProcessAllOverlappingPairs(check);
		}

		public static bool AabbOverlap(SimpleBroadphaseProxy proxyA, SimpleBroadphaseProxy proxyB)
		{
			return proxyA.Minimum.X <= proxyB.Maximum.X && proxyB.Minimum.X <= proxyA.Maximum.X &&
				   proxyA.Minimum.Y <= proxyB.Maximum.Y && proxyB.Minimum.Y <= proxyA.Maximum.Y &&
				   proxyA.Minimum.Z <= proxyB.Maximum.Z && proxyB.Minimum.Z <= proxyA.Maximum.Z;
		}

		private void Validate()
		{
			for (int i = 0; i < _proxies.Count; i++)
			{
				for (int j = i + 1; j < _proxies.Count; j++)
				{
					if (_proxies[i] == _proxies[j])
						throw new BulletException();
				}
			}
		}
	}

	public class CheckOverlapCallback : IOverlapCallback
	{
		public bool ProcessOverlap(ref BroadphasePair pair)
		{
			return (!SimpleBroadphase.AabbOverlap(pair.ProxyA as SimpleBroadphaseProxy, pair.ProxyB as SimpleBroadphaseProxy));
		}
	}
}
